import { ElMessageBox, ElLoading, ElStep } from "element-plus";
import { Time } from "./time";
import { shallowReactive, watch, type Reactive } from 'vue';
import { ElMessage } from "element-plus";
import { showDialog, showToast } from "vant";

class Utils {
    title: string = ''
    show: boolean = false
    loading: boolean = false
    hasChanged: boolean = false
    json: string[] = []
    isPhone: boolean = window.isPhone || false
    static VALEXP: { [key: string]: RegExp; } = { PHONE: /^1\d{10}$/ };
    static timer: number = 0

    constructor() {
        return shallowReactive(this)
    }
    setItem<T extends Record<string, any>>(labels: T, target: Reactive<T>) {
        if (!labels) return
        const keys = Object.keys(labels) as (keyof T & string)[]
        keys.forEach(item => {
            target[item] = labels[item]
        })
    }
    static utils_debounce(func: (...args: any[]) => void, delay: number = 500, ...arg: any[]) {
        if (this.timer) {
            clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
            func(...arg)
        }, delay)
    }
    showToast(msg: string = '', type: 'success' | 'warning' | 'error' = 'success') {
        if (this.isPhone) {
            showToast(msg)
        } else {
            ElMessage[type](msg)
        }
    }
    showConfirm(msg: string, title: string = '提示') {
        if (this.isPhone) {
            return showDialog({
                title,
                message: msg,
                confirmButtonText: '确定',
                cancelButtonText: '取消',
            })
        } else {
            return ElMessageBox.confirm(msg, title, {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            });
        }
    }
    showLoading(msg: string = '加载中...') {
        if (this.isPhone) {
            showToast({
                message: msg,
                type: 'loading'
            })
        } else {
            ElLoading.service({ lock: true, text: msg })
        }
    }

    watch<U extends keyof this>(key: U, cb: (value: this[U], oldValue: this[U]) => void) {
        watch(() => this[key], cb)
    }

    utils_readWrite<T extends Record<string, any>>(target: T): T {
        return new Proxy(target, {
            get(target: T, prop: PropertyKey): any {
                if (typeof prop === 'string' && prop.includes('.')) {
                    const keys = prop.split('.');
                    let current: any = target;
                    for (const key of keys) {
                        if (current && typeof current === 'object' && key in current) {
                            current = current[key];
                        } else {
                            return undefined;
                        }
                    }
                    return current;
                }
                return target[prop as keyof T];
            },
            set(target: T, prop: PropertyKey, value: any): boolean {
                if (typeof prop === 'string' && prop.includes('.')) {
                    const keys = prop.split('.');
                    let current: any = target || {};
                    for (const key of keys.slice(0, -1)) {
                        if (current && typeof current === 'object' && key in current) {
                            const next = current[key]
                            if (!next || typeof next !== 'object') {
                                current[key] = {}
                            }
                            current = current[key]
                        } else {
                            current[key] = {};
                            current = current[key];
                        }
                    }
                    current[keys[keys.length - 1]] = value;
                    return true;
                }
                target[prop as keyof T] = value;
                return true;
            }
        });
    }
    utils_getdate(date: string | number = new Date().toLocaleString()): Time {
        return new Time(date)
    }
    utils_confirm() {
        if (!localStorage.getItem('unConfirm')) {
            return new Promise((res) => {
                res(true)
            })
        } else {
            return ElMessageBox.confirm(
                '关闭将不保留数据，是否确认',
                {
                    confirmButtonText: '确认',
                    cancelButtonText: '取消',
                    type: 'warning',
                }
            )
        }
    }
    utils_isEmpty(val: string | number | boolean | object | undefined | null) {
        return val === undefined || val === null || val === ''
    }

    utils_proxy_set<T extends object>(target: T, cb: <U extends keyof T>(target: T, key: U, value: T[U], recerver: T) => any): T {
        return new Proxy(target, {
            set: (target: T, key: PropertyKey, value: any, recerver: T) => {
                const v = cb(target, key as keyof T, value, recerver)
                const val = v !== undefined ? v : value
                return Reflect.set(target, key, val, recerver)
            }
        })
    }
    utils_hasChanged(porxyary?: string[]) {
        return new Proxy(this, {
            set: (target, key: string, value, recerver) => {
                if (porxyary) {
                    if (porxyary.includes(key)) {
                        if (target.hasChanged === false) {
                            recerver.hasChanged = true
                        }
                    }
                } else {
                    if (key !== "hasChanged") {
                        if (target.hasChanged === false) {
                            recerver.hasChanged = true
                        }
                    }
                }
                return Reflect.set(target, key, value, recerver)
            }
        })
    }
    utils_parames(obj: { [key: string]: string | number | boolean | object | null | undefined }, url: string = '') {
        if (!obj) return url
        if (!url.includes('?')) url += '?'
        else url += '&'
        const s: string[] = [];
        Object.keys(obj).forEach(key => {
            let value = obj[key]
            if (value instanceof Object) {
                value = JSON.stringify(value)
            }
            s.push(key + '=' + value + '&');
        });
        const n = s.join('');
        return url + n.replace(/&$/, '');
    }
    static deepForeach<U extends string, T extends { [key: string]: any, parent?: T }>(target: T[] | undefined, cb: (value: T, parent: T | null, parents: T[]) => void, { child }: { child: U } = { child: 'children' as U }) {
        const fun = (children: T[] | undefined, parents: T[], parent: T | null) => {
            if (!children) return
            children.forEach(item => {
                if (!item) return
                const c = item[child]
                cb(item, parent, parents.concat(item))
                return c ? fun(c, parents.concat(item), item) : item
            })
        }
        fun(target, [], null)
    }
}

export {
    Utils
}